package org.flik.server.bean;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;

import org.flik.server.ServerUtils;
import org.flik.server.entity.FlikUser;
import org.flik.server.entity.Project;
import org.flik.server.entity.Ticket;
import org.flik.server.entity.TicketCategory;
import org.flik.server.entity.TicketComment;
import org.flik.server.entity.TicketStatus;
import org.flik.server.entity.TicketType;

import com.butlerpress.dict.Dictionary;

@Stateless
@LocalBean
public class EntityTestDataGeneratorBean {
    
	private static final int MAX_TICKETS_PER_PROJECT = 10;//400;
	private static final int MIN_TICKETS_PER_PROJECT = 50;//50;
	private static final int MAX_TICKET_COMMENTS = 10;
	private static final int MAX_PROJECTS = 5;//15;
	private static final int MAX_USERS = 10;
	private static final int MIN_USERS = 1;
	private GenericBean genericBean = ServerUtils.lookupBean(GenericBean.class);
	private String[] ticketCategories = {"Build", "Compiler", "DevMode", "DevPlugin", "Documentation", "EclipsePlugin", 
			"I18N", "JRE", "Maven", "Other", "RPC", "Testing", "UI"}; 
	private String[] ticketType = {"Defect", "Feature", "Other", "Task"}; 
	private String[] ticketStatus = {"Accepted", "FixedNotReleased", "NeedsInfo", "New", "PatchesWelcome", "ReviewPending", "Started"}; 
	
	@PersistenceContext(unitName = "flik", type = PersistenceContextType.EXTENDED)
	private EntityManager entityManager;
	
	public ArrayList<FlikUser> generateFlikUser(){
		ArrayList<FlikUser> ret = new ArrayList<FlikUser>();
		getUniqueProperNames(getRandomNumberBetween(MIN_USERS, MAX_USERS));
		for (int i = 0; i<MAX_USERS; i++){
			String firstName = Dictionary.getRandomProperName(); 
			String lastName = Dictionary.getRandomProperName(); 
			ret.add(genericBean.create(new FlikUser(firstName.toLowerCase(), firstName.toLowerCase(), firstName, lastName, firstName + "@" + Dictionary.getRandomWord() + ".com")));
		}
		return ret;
	}
	private ArrayList<String> getUniqueProperNames(int max){
		Set<String> properNames = new HashSet<String>(); 
		for (int i = 0; i<max; i++)
			properNames.add(Dictionary.getRandomProperName());
		return new ArrayList<String>(properNames); 
		
	}
	private ArrayList<TicketCategory> generateTicketCategory() {
		ArrayList<TicketCategory> ret = new ArrayList<TicketCategory>();
		for (String ticketCategory: ticketCategories)
			ret.add(genericBean.create(new TicketCategory(ticketCategory)));
		return ret;
	}
	
	private ArrayList<TicketCategory> getRandomCategory(ArrayList<TicketCategory> ticketCategories) {
		HashSet<TicketCategory> ret = new HashSet<TicketCategory>();
		int catSize = ticketCategories.size(); 
		double size = Math.random() * catSize; 
		for (int i=0; i<size; i++)
			ret.add(ticketCategories.get((int)(Math.random() * size)));
		return new ArrayList<TicketCategory>(ret); 
	}
	
	private ArrayList<Project> generateProject(ArrayList<TicketCategory> ticketCategories) {
		ArrayList<Project> ret = new ArrayList<Project>();
		for (int i = 0; i<MAX_PROJECTS; i++)
			ret.add(genericBean.create(new Project(Dictionary.getRandomWordTermCommonNameOrConnector(), getRandomCategory(ticketCategories))));
		return ret;
	}
	
	private ArrayList<TicketStatus> generateTicketStatus() {
		ArrayList<TicketStatus> ret = new ArrayList<TicketStatus>();
		for (int i = 0; i<ticketStatus.length; i++)
			ret.add(genericBean.create(new TicketStatus(ticketStatus[i])));
		return ret;
	}
	private ArrayList<TicketType> generateTicketTypes() {
		ArrayList<TicketType> ret = new ArrayList<TicketType>();
		for (int i = 0; i<ticketType.length; i++)
			ret.add(genericBean.create(new TicketType(ticketType[i])));
		return ret;
	}

	private ArrayList<Ticket> generateTickets(ArrayList<FlikUser> reportedByUsers, ArrayList<TicketType> ticketTypes, ArrayList<Project> projects, ArrayList<TicketStatus> ticketStatuses) {
		ArrayList<Ticket> ret = new ArrayList<Ticket>();
		
		for (Project project: projects)
			for (int i=0; i<getRandomNumberBetween(MIN_TICKETS_PER_PROJECT, MAX_TICKETS_PER_PROJECT) ; i++){
				FlikUser reportedBy = selectRandom(reportedByUsers);
				Ticket ticket = genericBean.create(new Ticket(reportedBy, selectRandom(ticketTypes), selectRandom(ticketStatuses), selectRandom(reportedByUsers), project, generateSentence(5, 15),
//						generateComments(new ArrayList<TicketComment>(), 50)
//						generateComments(new TicketComment(reportedBy, new Date(), generateParagraphs(2, 7, 2, 7, 5, 15), null), reportedByUsers, MAX_TICKET_COMMENTS)
						null
						)
						); 
				ret.add(ticket);
				ticket.setTicketComment(generateComments(new TicketComment(reportedBy, generateParagraphs(2, 7, 2, 7, 5, 15), null, ticket), reportedByUsers, MAX_TICKET_COMMENTS, ticket));
			}
		
//		for(FlikUser reportedBy: reportedByUsers)
		return ret;
	}
	private TicketComment generateComments(TicketComment ticketComment, ArrayList<FlikUser> reportedByUsers, int maxComments, Ticket ticket) {
		ArrayList<TicketComment> parentTickets = new ArrayList<TicketComment>();
		parentTickets.add(ticketComment);
		generateComments(reportedByUsers, parentTickets, maxComments, ticket);
		return ticketComment; 
	}

	private void generateComments(ArrayList<FlikUser> reportedByUsers, ArrayList<TicketComment> parentTickets, int maxComments, Ticket ticket) {
		if (maxComments > 0){
			TicketComment tc = genericBean.create(new TicketComment(selectRandom(reportedByUsers), generateParagraphs(2, 7, 2, 7, 5, 15), selectRandom(parentTickets), ticket));
			parentTickets.add(tc);
			generateComments(reportedByUsers, parentTickets, --maxComments, ticket);
		}
	}

//	private ArrayList<TicketComment> generateTicketComments(ArrayList<Ticket> tickets, ArrayList<FlikUser> reportedByUsers, int minComments, int maxComments) {
//		ArrayList<TicketComment> ret = new ArrayList<TicketComment>();
//		Set<TicketComment> availableReplyTo = new HashSet<TicketComment>();
//		for (Ticket ticket: tickets){
//			availableReplyTo.clear();
//			availableReplyTo.add(ticket.getTicketComment());
//			int numOfComments = getRandomNumberBetween(minComments, maxComments);
//			for (int i=0; i<numOfComments; i++){
//				TicketComment ticketComment = new TicketComment(selectRandom(reportedByUsers), new Date(), generateParagraphs(2, 7, 2, 7, 5, 15), Math.random() > 0.6?selectRandom(new ArrayList<TicketComment>(availableReplyTo)):null); 				
////				TicketComment ticketComment = new TicketComment(selectRandom(reportedByUsers), new Date(), generateParagraphs(2, 7, 2, 7, 5, 15), null); 				
//				ret.add(genericBean.create(ticketComment));
//
//				availableReplyTo.add(ticketComment);
//			}
//		}
//		return ret;
//	}


	public static String generateParagraphs(int minParagraphs, int maxParagraphs, int minSentences, int maxSentences, int minWords, int maxWords){
		int numOfParagraphs = getRandomNumberBetween(minParagraphs, maxParagraphs);//((int)(Math.random() * (maxParagraphs - minParagraphs) ))+ minParagraphs;
		String ret = ""; 
		for (int i = 0; i < numOfParagraphs; i++)
			ret += generateParagraph(minSentences, maxSentences, minWords, maxWords) + "\n\n";
		return ret;
	}
	
	public static String generateParagraph(int minSentences, int maxSentences, int minWords, int maxWords){
		int numOfSentences = getRandomNumberBetween(minSentences, maxSentences);//((int)(Math.random() * (maxSentences - minSentences) ))+ minSentences;
		String ret = "";
		for (int i = 0; i < numOfSentences; i++)
			ret += generateSentence(minWords, maxWords) + ". ";
		return ret;
		
	}
	
	public static String generateSentence(int minWords, int maxWords){
		int numOfWords = getRandomNumberBetween(minWords, maxWords);//((int)(Math.random() * (maxWords - minWords) )) + minWords;
		String ret = ""; 
		for (int i = 0; i < numOfWords; i++)
			ret += Dictionary.getRandomWord() + " ";
		return ret.trim();
	}
	@SuppressWarnings("unused")
	private <T> T selectRandom(T[] list){
		if (list.length == 0) return null; 
		return list[(int)(Math.random() * (list.length))];
	}
	private <T> T selectRandom(ArrayList<T> list){
		if (list.size() == 0) return null; 
		return list.get((int)(Math.random() * (list.size())));
	}
	public void populate(){
		ArrayList<FlikUser> flikUsers = generateFlikUser();
		ArrayList<TicketCategory> ticketCategories = generateTicketCategory();
		ArrayList<Project> projects = generateProject(ticketCategories);
		ArrayList<TicketStatus> ticketStatuses = generateTicketStatus();
		ArrayList<TicketType> ticketTypes = generateTicketTypes();
		ArrayList<Ticket> tickets = generateTickets(flikUsers, ticketTypes, projects, ticketStatuses);
		System.out.println("Generated: " + tickets.size() + " tickets!");
	}
	

	public boolean getRandomBoolean(){
		return Math.random() <= 0.5;
	}
	
	public static int getRandomNumberBetween(int min, int max){
		return ((int)(Math.random() * (max - min) ))+ min;
	}
	
	public void dropEntities() {
		entityManager.createNativeQuery("drop table if exists flikuser, project, ticket, ticket_category_project, ticketcategory, ticketstatus, tickettype, ticketcomment").executeUpdate();
	}
}
